{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PicoRV32 Processor Mixed-Memory Processor Demo\n",
    "\n",
    "This notebook demonstrates using Jupyter Notebooks and IPython Magics to run C/C++ and assembly code on a PicoRV32 Processor. \n",
    "\n",
    "The PicoRV32 Processor in this example is a Mixed-Memory processor. This means it has a 64-KB BRAM Memory space.\n",
    "\n",
    "When arguments are passed to the PicoRV32 processor for execution they will be copied and passed in **BRAM Memory** as PYNQ Contiguous Memory Allocated (CMA) arrays. Previously allocated CMA arrays passed as arguments will not be copied, and reused.\n",
    "\n",
    "When the program terminates, results are back-propogated "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading the Overlay\n",
    "\n",
    "To begin, import the overlay using the following cell. This also loads the IPython Magics: `riscvc`, `riscvcpp`, and `riscvasm`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes[\n",
       "      'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes['magic_text/x-asmx'] = {'reg':[/^%%riscvasm/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes['magic_text/x-csrc'] = {'reg':[/^%%riscvc/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes['magic_text/x-c++src'] = {'reg':[/^%%riscvcpp/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from riscvonpynq.picorv32.bram.picorv32 import Overlay\n",
    "overlay = Overlay(\"picorv32.bit\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can examine the overlay using the `help()` method. This overlay is a subclass of riscvonpynq.Overlay, which itself is a subclass of pynq.Overlay."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on Overlay in module riscvonpynq.picorv32.bram.picorv32 object:\n",
      "\n",
      "class Overlay(riscvonpynq.Overlay.Overlay)\n",
      " |  Overlay driver for the PicoRV32 bram Overlay\n",
      " |  \n",
      " |  Note\n",
      " |  ----\n",
      " |  This class definition must be co-located with the .tcl and .bit\n",
      " |  file for the overlay for the search path modifications in\n",
      " |  riscvonpynq.Overlay to work. __init__ in riscvonpynq.Overlay uses\n",
      " |  the path of this file to search for the .bit file using the\n",
      " |  inspect package.\n",
      " |  \n",
      " |  Method resolution order:\n",
      " |      Overlay\n",
      " |      riscvonpynq.Overlay.Overlay\n",
      " |      pynq.overlay.Overlay\n",
      " |      pynq.pl.Bitstream\n",
      " |      builtins.object\n",
      " |  \n",
      " |  Methods inherited from riscvonpynq.Overlay.Overlay:\n",
      " |  \n",
      " |  __init__(self, bitfile, **kwargs)\n",
      " |      Return a new Overlay object, with an amended search path.\n",
      " |      \n",
      " |      The following lines enable a PYNQ-Like API for Overlays. For\n",
      " |      example, without these lines you cannot call\n",
      " |      streamOverlay('stream.bit') if stream.bit is not in the PYNQ\n",
      " |      package. because stream.bit is not on the bitstream search\n",
      " |      path. \n",
      " |      \n",
      " |      This class fixes that by searching the location of subclass\n",
      " |      definition if an absolute path is not provided.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      bitfile : str\n",
      " |          The bitstream name or absolute path as a string.\n",
      " |      download : boolean or None\n",
      " |          Whether the overlay should be downloaded. If None then the\n",
      " |          overlay will be downloaded if it isn't already loaded.\n",
      " |      \n",
      " |      Note\n",
      " |      ----\n",
      " |      This class requires a Vivado '.tcl' file to be next to bitstream file\n",
      " |      with same name (e.g. base.bit and base.tcl).\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from pynq.overlay.Overlay:\n",
      " |  \n",
      " |  __dir__(self)\n",
      " |      __dir__() -> list\n",
      " |      default dir() implementation\n",
      " |  \n",
      " |  __getattr__(self, key)\n",
      " |      Overload of __getattr__ to return a driver for an IP or\n",
      " |      hierarchy. Throws an `RuntimeError` if the overlay is not loaded.\n",
      " |  \n",
      " |  download(self)\n",
      " |      The method to download a bitstream onto PL.\n",
      " |      \n",
      " |      Note\n",
      " |      ----\n",
      " |      After the bitstream has been downloaded, the \"timestamp\" in PL will be\n",
      " |      updated. In addition, all the dictionaries on PL will\n",
      " |      be reset automatically.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      None\n",
      " |  \n",
      " |  is_loaded(self)\n",
      " |      This method checks whether a bitstream is loaded.\n",
      " |      \n",
      " |      This method returns true if the loaded PL bitstream is same\n",
      " |      as this Overlay's member bitstream.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      bool\n",
      " |          True if bitstream is loaded.\n",
      " |  \n",
      " |  load_ip_data(self, ip_name, data)\n",
      " |      This method loads the data to the addressable IP.\n",
      " |      \n",
      " |      Calls the method in the super class to load the data. This method can\n",
      " |      be used to program the IP. For example, users can use this method to\n",
      " |      load the program to the Microblaze processors on PL.\n",
      " |      \n",
      " |      Note\n",
      " |      ----\n",
      " |      The data is assumed to be in binary format (.bin). The data name will\n",
      " |      be stored as a state information in the IP dictionary.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      ip_name : str\n",
      " |          The name of the addressable IP.\n",
      " |      data : str\n",
      " |          The absolute path of the data to be loaded.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      None\n",
      " |  \n",
      " |  reset(self)\n",
      " |      This function resets all the dictionaries kept in the overlay.\n",
      " |      \n",
      " |      This function should be used with caution.\n",
      " |      \n",
      " |      Returns\n",
      " |      -------\n",
      " |      None\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors inherited from pynq.pl.Bitstream:\n",
      " |  \n",
      " |  __dict__\n",
      " |      dictionary for instance variables (if defined)\n",
      " |  \n",
      " |  __weakref__\n",
      " |      list of weak references to the object (if defined)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(overlay)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also examine the RISC-V Processor in the overlay. It is named picoAxiProcessor. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on Processor in module riscvonpynq.picorv32.bram.picorv32 object:\n",
      "\n",
      "class Processor(riscvonpynq.Processor.BramProcessor)\n",
      " |  Hierarchy driver for the PicoRV32 BRAM Processor\n",
      " |  \n",
      " |  Note\n",
      " |  ----\n",
      " |  In order to be recognized as a RISC-V Processor hierarchy, three\n",
      " |  conditions must be met: First, there must be a PS-Memory-Mapped\n",
      " |  Block RAM Controller where the name matches the variable\n",
      " |  _bram. Second, the hierarchy name (fullpath) must equal the\n",
      " |  variable _name. Finally, there must be a GPIO port with the name\n",
      " |  _reset_name.\n",
      " |  \n",
      " |  Subclasses of this module are responsible for setting _name (The\n",
      " |  name of the Hierarchy), _bits (Processor bit-width), _proc\n",
      " |  (Processor Type Name)\n",
      " |  \n",
      " |  This class must be placed in a known location relative to the\n",
      " |  build files for this processor. The relative path can be modified\n",
      " |  in __get_path.\n",
      " |  \n",
      " |  Method resolution order:\n",
      " |      Processor\n",
      " |      riscvonpynq.Processor.BramProcessor\n",
      " |      riscvonpynq.Processor.Processor\n",
      " |      pynq.overlay.DefaultHierarchy\n",
      " |      pynq.overlay._IPMap\n",
      " |      builtins.object\n",
      " |  \n",
      " |  Methods defined here:\n",
      " |  \n",
      " |  __init__(self, description, *args)\n",
      " |      Return a new Processor object. \n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      description : dict\n",
      " |          Dictionary describing this processor.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Class methods defined here:\n",
      " |  \n",
      " |  checkhierarchy(description) from pynq.overlay.RegisterHierarchy\n",
      " |      Function to check if the driver matches a particular hierarchy\n",
      " |      \n",
      " |      This function should be redefined in derived classes to return True\n",
      " |      if the description matches what is expected by the driver. The default\n",
      " |      implementation always returns False so that drivers that forget don't\n",
      " |      get loaded for hierarchies they don't expect.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from riscvonpynq.Processor.Processor:\n",
      " |  \n",
      " |  land(self)\n",
      " |      Terminate execution on a RISC-V Processor, unload the program and\n",
      " |      arguments, and return the program's return value (if it terminated). \n",
      " |      \n",
      " |      Note\n",
      " |      ----\n",
      " |      Any modified data in the program argument buffers will be\n",
      " |      copied back to the original buffer (if applicable) by _unload()\n",
      " |  \n",
      " |  launch(self, prog, *args)\n",
      " |      Launch a given program on the RISC-V Processor, and return while\n",
      " |      the program executes.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      prog : riscvonpynq.Program\n",
      " |          A Program class from the riscvonpynq library that wraps a\n",
      " |          user program\n",
      " |      \n",
      " |      args : tuple\n",
      " |          Arguments to pass to the main method of the program\n",
      " |  \n",
      " |  run(self, prog, *args)\n",
      " |      Run a given program on the RISC-V Processor, and block until the\n",
      " |      program terminates.\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      prog : riscvonpynq.Program\n",
      " |          A Program class from the riscvonpynq library that wraps a\n",
      " |          user program\n",
      " |      \n",
      " |      args : tuple\n",
      " |          Arguments to pass to the main method of the program\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors inherited from riscvonpynq.Processor.Processor:\n",
      " |  \n",
      " |  bits\n",
      " |      Return the bit width of the RISC-V Processor IP\n",
      " |  \n",
      " |  build_path\n",
      " |      Return the path to the build directory for this RISC-V Processor\n",
      " |  \n",
      " |  name\n",
      " |      Return the name of the RISC-V Processor Hierarchy\n",
      " |  \n",
      " |  proc\n",
      " |      Return the name of the RISC-V Processor IP RISC-V Processor\n",
      " |      Hierarchy\n",
      " |  \n",
      " |  stkptr\n",
      " |      Return the memory size in Bytes of the desired stack pointer\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Methods inherited from pynq.overlay._IPMap:\n",
      " |  \n",
      " |  __dir__(self)\n",
      " |      __dir__() -> list\n",
      " |      default dir() implementation\n",
      " |  \n",
      " |  __getattr__(self, key)\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors inherited from pynq.overlay._IPMap:\n",
      " |  \n",
      " |  __dict__\n",
      " |      dictionary for instance variables (if defined)\n",
      " |  \n",
      " |  __weakref__\n",
      " |      list of weak references to the object (if defined)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(overlay.processor)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This demonstrates that processor is an instance of riscvonpynq.Processor.BramProcessor. As we stated above, this means that the processor is connected to BRAM and DDR. riscvonpynq.Processor.BramProcessor is an indirect subclass of pynq.overlay.DefaultHierarchy -- this means that the processor is actually a collection of IP wrapped in an Block Diagram Editor IP Hierarchy that is recognized by pynq using the `checkhierarchy` method.\n",
    "\n",
    "The BramProcessor class provides methods to run, launch (run a program asynchronously), and land (stop an asynchronous program). You can see further documentation in the cell below: "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## RISC-V Magics\n",
    "\n",
    "Our package provides three RISC-V Magics. The first is `riscvc`, which compiles C code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre>Compilation of program test SUCCEEDED</pre>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%riscvc test overlay.processor\n",
    "\n",
    "int main(int argc, char ** argv){\n",
    "    unsigned int * a = (unsigned int *)argv[1];\n",
    "    return a[2];\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can run the test program above and pass it arguments. The arguments must be a Numpy type. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Passed!\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "arg1 = np.array(range(1, 10), np.uint32)\n",
    "retval = overlay.processor.run(test, arg1)\n",
    "\n",
    "if(retval != arg1[2]):\n",
    "    print(\"Test Failed!\")\n",
    "else:\n",
    "    print(\"Test Passed!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The RISC-V Processor lets the ARM Processor know it is complete by raising the IRQ line. Each processor can do this in a different way. For example, the PicoRV32 processor has a `trap` pin that is raised on an `ebreak` instruction. Other processors must write to GPIO pins. \n",
    "\n",
    "You can see the IRQ line in the overlay: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on Interrupt in module pynq.interrupt object:\n",
      "\n",
      "class Interrupt(builtins.object)\n",
      " |  Class that provides the core wait-based API to end users\n",
      " |  \n",
      " |  Provides a single coroutine wait that waits until the interrupt\n",
      " |  signal goes high. If the Overlay is changed or re-downloaded this\n",
      " |  object is invalidated and waiting results in undefined behaviour.\n",
      " |  \n",
      " |  Methods defined here:\n",
      " |  \n",
      " |  __init__(self, pinname)\n",
      " |      Initialise an Interrupt object attached to the specified pin\n",
      " |      \n",
      " |      Parameters\n",
      " |      ----------\n",
      " |      pinname : string\n",
      " |          Fully qualified name of the pin in the block diagram of the\n",
      " |          for ${cell}/${pin}. Raises an exception if the pin cannot\n",
      " |          be found in the currently active Overlay\n",
      " |  \n",
      " |  wait(self)\n",
      " |      Wait for the interrupt to be active\n",
      " |      \n",
      " |      May raise an exception if the Overlay has been changed since\n",
      " |      initialisation.\n",
      " |  \n",
      " |  ----------------------------------------------------------------------\n",
      " |  Data descriptors defined here:\n",
      " |  \n",
      " |  __dict__\n",
      " |      dictionary for instance variables (if defined)\n",
      " |  \n",
      " |  __weakref__\n",
      " |      list of weak references to the object (if defined)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(overlay.processor.irq)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also examine the processor's memory: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Memory Index   0: 0x00000013\n",
      "Memory Index   1: 0x00000093\n",
      "Memory Index   2: 0x00008137\n",
      "Memory Index   3: 0x00000193\n",
      "Memory Index   4: 0x00000213\n",
      "Memory Index   5: 0x00000293\n",
      "Memory Index   6: 0x00000313\n",
      "Memory Index   7: 0x00000393\n",
      "Memory Index   8: 0x00000413\n",
      "Memory Index   9: 0x00000493\n",
      "Memory Index  10: 0xffc12503\n",
      "Memory Index  11: 0xff812583\n",
      "Memory Index  12: 0x00000613\n",
      "Memory Index  13: 0x00000693\n",
      "Memory Index  14: 0x00000713\n",
      "Memory Index  15: 0x00000793\n",
      "Memory Index  16: 0x00000813\n",
      "Memory Index  17: 0x00000893\n",
      "Memory Index  18: 0x00000913\n",
      "Memory Index  19: 0x00000993\n",
      "Memory Index  20: 0x00000a13\n",
      "Memory Index  21: 0x00000a93\n",
      "Memory Index  22: 0x00000b13\n",
      "Memory Index  23: 0x00000b93\n",
      "Memory Index  24: 0x00000c13\n",
      "Memory Index  25: 0x00000c93\n",
      "Memory Index  26: 0x00000d13\n",
      "Memory Index  27: 0x00000d93\n",
      "Memory Index  28: 0x00000e13\n",
      "Memory Index  29: 0x00000e93\n",
      "Memory Index  30: 0x00000f13\n",
      "Memory Index  31: 0x00000f93\n",
      "Memory Index  32: 0x010000ef\n",
      "Memory Index  33: 0xfeb12c23\n",
      "Memory Index  34: 0xfea12e23\n",
      "Memory Index  35: 0x00100073\n",
      "Memory Index  36: 0x0045a783\n",
      "Memory Index  37: 0x0087a503\n",
      "Memory Index  38: 0x00008067\n",
      "Memory Index  39: 0x00000000\n",
      "Memory Index  40: 0x00000000\n",
      "Memory Index  41: 0x00000000\n",
      "Memory Index  42: 0x00000000\n",
      "Memory Index  43: 0x00000000\n",
      "Memory Index  44: 0x00000000\n",
      "Memory Index  45: 0x00000000\n",
      "Memory Index  46: 0x00000000\n",
      "Memory Index  47: 0x00000000\n",
      "Memory Index  48: 0x00000000\n",
      "Memory Index  49: 0x00000000\n",
      "Memory Index  50: 0x00000000\n",
      "Memory Index  51: 0x00000000\n",
      "Memory Index  52: 0x00000000\n",
      "Memory Index  53: 0x00000000\n",
      "Memory Index  54: 0x00000000\n",
      "Memory Index  55: 0x00000000\n",
      "Memory Index  56: 0x00000000\n",
      "Memory Index  57: 0x00000000\n",
      "Memory Index  58: 0x00000000\n",
      "Memory Index  59: 0x00000000\n",
      "Memory Index  60: 0x00000000\n",
      "Memory Index  61: 0x00000000\n",
      "Memory Index  62: 0x00000000\n",
      "Memory Index  63: 0x00000000\n",
      "Memory Index  64: 0x00000000\n",
      "Memory Index  65: 0x00000000\n",
      "Memory Index  66: 0x00000000\n",
      "Memory Index  67: 0x00000000\n",
      "Memory Index  68: 0x00000000\n",
      "Memory Index  69: 0x00000000\n",
      "Memory Index  70: 0x00000000\n",
      "Memory Index  71: 0x00000000\n",
      "Memory Index  72: 0x00000000\n",
      "Memory Index  73: 0x00000000\n",
      "Memory Index  74: 0x00000000\n",
      "Memory Index  75: 0x00000000\n",
      "Memory Index  76: 0x00000000\n",
      "Memory Index  77: 0x00000000\n",
      "Memory Index  78: 0x00000000\n",
      "Memory Index  79: 0x00000000\n",
      "Memory Index  80: 0x00000000\n",
      "Memory Index  81: 0x00000000\n",
      "Memory Index  82: 0x00000000\n",
      "Memory Index  83: 0x00000000\n",
      "Memory Index  84: 0x00000000\n",
      "Memory Index  85: 0x00000000\n",
      "Memory Index  86: 0x00000000\n",
      "Memory Index  87: 0x00000000\n",
      "Memory Index  88: 0x00000000\n",
      "Memory Index  89: 0x00000000\n",
      "Memory Index  90: 0x00000000\n",
      "Memory Index  91: 0x00000000\n",
      "Memory Index  92: 0x00000000\n",
      "Memory Index  93: 0x00000000\n",
      "Memory Index  94: 0x00000000\n",
      "Memory Index  95: 0x00000000\n",
      "Memory Index  96: 0x00000000\n",
      "Memory Index  97: 0x00000000\n",
      "Memory Index  98: 0x00000000\n",
      "Memory Index  99: 0x00000000\n",
      "Memory Index 100: 0x00000000\n",
      "Memory Index 101: 0x00000000\n",
      "Memory Index 102: 0x00000000\n",
      "Memory Index 103: 0x00000000\n",
      "Memory Index 104: 0x00000000\n",
      "Memory Index 105: 0x00000000\n",
      "Memory Index 106: 0x00000000\n",
      "Memory Index 107: 0x00000000\n",
      "Memory Index 108: 0x00000000\n",
      "Memory Index 109: 0x00000000\n",
      "Memory Index 110: 0x00000000\n",
      "Memory Index 111: 0x00000000\n",
      "Memory Index 112: 0x00000000\n",
      "Memory Index 113: 0x00000000\n",
      "Memory Index 114: 0x00000000\n",
      "Memory Index 115: 0x00000000\n",
      "Memory Index 116: 0x00000000\n",
      "Memory Index 117: 0x00000000\n",
      "Memory Index 118: 0x00000000\n",
      "Memory Index 119: 0x00000000\n",
      "Memory Index 120: 0x00000000\n",
      "Memory Index 121: 0x00000000\n",
      "Memory Index 122: 0x00000000\n",
      "Memory Index 123: 0x00000000\n",
      "Memory Index 124: 0x00000000\n",
      "Memory Index 125: 0x00000000\n",
      "Memory Index 126: 0x00000000\n",
      "Memory Index 127: 0x00000000\n"
     ]
    }
   ],
   "source": [
    "arr = overlay.processor.psBramController.mmio.array\n",
    "for i in range(128):  \n",
    "    print(f'Memory Index {i:3}: {arr[i]:#0{10}x}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We've also provided Magics for C++ (`riscvcpp`), and Assembly (`riscvasm`). These are demonstrated below: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre>Compilation of program test_cpp SUCCEEDED</pre>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%riscvcpp test_cpp overlay.processor\n",
    "\n",
    "class foo{\n",
    "    public:\n",
    "    static int mulby2(int val){\n",
    "        return val * 2;\n",
    "    }\n",
    "};\n",
    "\n",
    "int main(int argc, char ** argv){\n",
    "    int * a = (int *)argv[1];\n",
    "    return foo::mulby2(a[0]);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Passed!\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "test_cpp_arg = np.array([42], np.int32)\n",
    "retval = overlay.processor.run(test_cpp, test_cpp_arg)\n",
    "\n",
    "if(retval != test_cpp_arg*2):\n",
    "    print(\"Test Failed!\")\n",
    "else:\n",
    "    print(\"Test Passed!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, some assembly. `int argc` is in register `a0`, and `char **argv` is in register `a1`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre>Compilation of program test_asm SUCCEEDED</pre>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%riscvasm test_asm overlay.processor\n",
    "\n",
    ".global main\n",
    "\n",
    "main:\n",
    "    lw a2, 4(a1) # Get *argv[1]\n",
    "    lw a3, 0(a2) # Get argv[1]\n",
    "    addi a0, a3, -42 # Add -42, store in a0 (return register)\n",
    "    ret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test passed!\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "test_asm_arg = np.array([42], np.int32)\n",
    "retval = overlay.processor.run(test_asm, test_asm_arg)\n",
    "\n",
    "if(retval != test_asm_arg[0] + (-42)):\n",
    "    print('Test failed!')\n",
    "else:\n",
    "    print('Test passed!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And that's it!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
